using System;
using System.Collections.Generic;

using Cairo;
using Gtk;

using stefc.geo.platform;
using stefc.geo.lib;

namespace MyLocate
{

	class GtkCanvas : ICanvas
	{
		private readonly Context context;
		private readonly Dictionary<Int32,Color> colors;

		public GtkCanvas (Context context, int width, int height)
		{
			this.context=context;
			
			this.colors=new Dictionary<int, Color>();
			
			// nullpunkt des koordinaten systems in die mitte setzen
			context.Translate(width/2, height/2);
		}
		
		public void FillRect(double x, double y, 
		                     double width, double height, 
		                     Int32 color)
		{
			context.Rectangle(x,y,width,height);
			this.Fill(color);
		}
		
		public void SelectFont(string fontName, bool italic, bool bold)
		{
			context.SelectFontFace(fontName, 
			                       italic ? FontSlant.Italic: FontSlant.Normal,
			                       bold ? FontWeight.Bold : FontWeight.Normal);
		}
		
		public void TextOut(Cartesian coord, string text, double fontsize,  
						 Int32 foreground, Int32 shadow, Int32 background)
		{
			context.SetFontSize(fontsize);
			TextExtents te = context.TextExtents(text);
			double x1=coord.X - te.Width/2 - te.XBearing;
			double y1=coord.Y - te.Height/2 - te.YBearing;
			
			this.FillRect(x1+-1+te.XBearing,y1-1+te.YBearing,
			                te.Width+2,te.Height+2,background);
			
			this.DrawText(x1+1,y1+1,text,shadow);
			this.DrawText(x1,y1,text,foreground);	
		}
		
		public void Line(Cartesian start, Cartesian end, int lineWidth, Int32 color)
		{      
			context.LineWidth=lineWidth;
			context.Color=GetColor(color);
			context.NewPath();
			context.MoveTo(start.X,start.Y);
			context.LineTo(end.X,end.Y);
			context.Stroke();
		}
		
		public void Circle(double radius, int lineWidth, Int32 lineColor)
		{
			context.LineWidth=lineWidth;
			context.Color= GetColor(lineColor);
			
			context.NewPath();
			this.Circle(0, 0, radius);
			context.Stroke();
		}
		
		public void Circle(double radius, int lineWidth, Int32 lineColor, Int32 fillColor)
		{
			context.LineWidth=lineWidth;
			context.Color= GetColor(lineColor);
			
			context.NewPath();
			this.Circle(0, 0, radius);
			context.StrokePreserve();

			this.Fill(fillColor);
		}
		
		public void Pin(Cartesian coord, double radius, Int32 color)
		{
			double inner = radius*0.1;
			double ofs = radius / 2;
			
			double x = coord.X;
			double y = coord.Y;
			this.Circle(x+2,y+2, radius);
			this.Fill(ColorMapFactory.Black);
			
			Gradient radpat = new RadialGradient(x,y, radius, 
			                                     x-ofs,y-ofs, inner);
			
			radpat.AddColorStop(0, GetColor(color));
			radpat.AddColorStop(1, GetColor(ColorMapFactory.White));
			
			this.Circle(x,y,radius);
			context.Source = radpat;
			context.Fill();
		}
		
		#region Helper
		private Color GetColor(Int32 color)
		{
			if(this.colors.ContainsKey(color))
				return this.colors[color];
			byte r = (byte)((color & 0x00FF0000) >> 16); 
			byte g = (byte)((color & 0x0000FF00) >> 8); 
			byte b = (byte)(color & 0x000000FF);
			Color result = new Color(r/255.0d,g/255.0d,b/255.0d);
			this.colors.Add(color,result);
			return result;
		}
		
		private void Fill(Int32 color)
		{
			context.Color = this.GetColor(color);
			context.Fill();
		}
		
		private void Circle(double x, double y, double radius)
		{
			context.Arc(x,y, radius, 0, 2*Math.PI);
		}
		
		private void DrawText(double x, double y, string text, Int32 color)
		{
			context.Color=this.GetColor(color);
			context.MoveTo(x,y);
			context.ShowText(text);
		}
		#endregion
	}
}
